#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>

#define BUFLEN      (1024)
#define THREADNUM   (2)
#define CLIENTNUM   (1024)

int connect_host[CLIENTNUM];
int connect_num = 0;

static void *handle_request(void *argv){
    char buf[BUFLEN];
    int len;
    time_t now;
    int maxfd = -1;
    fd_set rfds;

    struct timeval tv;
    tv.tv_sec = 1;
    tv.tv_usec = 0;

    int i = 0;
    int err = -1;

    while (1) {
        FD_ZERO(&rfds);
        for (i = 0; i < CLIENTNUM; i++) {
            if (connect_host[i] != -1) {
                FD_SET(connect_host[i], &rfds);
                if (maxfd < connect_host[i])
                    maxfd = connect_host[i];
            }
        }
        err = select(maxfd + 1, &rfds, NULL, NULL, &tv);
        switch (err) {
            case 0:
                break;
            case -1:
                break;
            default:
                if (connect_num < 0)
                    break;
                for (i = 0; i < CLIENTNUM; i++) {
                    if (connect_host[i] != -1) {
                        /*FD_ISSET  判断描述符fd是否在给定的描述符集fdset中*/
                        if (FD_ISSET(connect_host[i], &rfds)) {
                            /*处理客户端请求*/
                            bzero(buf, BUFLEN);
                            len = recv(connect_host[i], buf, BUFLEN, 0);
                            if (len > 0 && !strncmp(buf, "TIME", 4)) {
                                bzero(buf, BUFLEN);
                                /*获取系统当前时间*/
                                now = time(NULL);
                                /*ctime将系统时间转换为字符串，sprintf使转化后的字符串保存在buf*/
                                sprintf(buf, "%24s\r\n", ctime(&now));
                                /*发送系统时间*/
                                send(connect_host[i], buf, strlen(buf), 0);
                            }
                            /*关闭通讯的套接字*/
                            close(connect_host[i]);
                            /*更新文件描述符在数组中的值*/
                            connect_host[i] = -1;
                            connect_num--; 
                        }
                    }            
                }
                break;
        }
    }
    return NULL;
}

static void *handle_connect(void *arg)
{
    int sockfd = *((int *)arg);
    int newfd;
    struct sockaddr_in c_addr;
    socklen_t len;
    int i;

    while (1) {
        len = sizeof(struct sockaddr);
        if ((newfd = accept(sockfd,(struct sockaddr *)&c_addr,
                                                    &len)) > 0) {
            printf("\n*****************通信开始***************\n");
            printf("正在与您通信的客户端是：%s: %d\n",
                        inet_ntoa(c_addr.sin_addr),
                        ntohs(c_addr.sin_port));

            for (i = 0; i < CLIENTNUM; i++) {
                if (connect_host[i] == -1) {
                    connect_host[i] = newfd;
                    /*客户端计数器*/
                    connect_num++;
                    /*继续等待新的客户端*/
                    break;            
                }
            }
        }
    }
    return NULL;
}

int main(int argc, char **argv)
{
    int sockfd, i;
    struct sockaddr_in s_addr;
    unsigned int port, listnum;
    pthread_t thread_s[2];
    
    memset(connect_host, -1, CLIENTNUM);

    /*建立socket*/
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(errno);
    } else
        printf("socket create success!\n");

    /*设置服务器端口*/    
    if(argv[2])
        port = atoi(argv[2]);
    else
        port = 4567;

    /*设置侦听队列长度*/
    if(argv[3])
        listnum = atoi(argv[3]);
    else
        listnum = 3;

    /*设置服务器ip*/
    bzero(&s_addr, sizeof(s_addr));
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(port);
    if (argv[1])
        s_addr.sin_addr.s_addr = inet_addr(argv[1]);
    else
        s_addr.sin_addr.s_addr = INADDR_ANY;

    /*把地址和端口绑定到套接字上*/
    if ((bind(sockfd, (struct sockaddr *)&s_addr,
                        sizeof(struct sockaddr))) == -1) {
        perror("bind");
        exit(errno);
    } else
        printf("bind success!\n");

    /*侦听本地端口*/
    if (listen(sockfd, listnum) == -1) {
        perror("listen");
        exit(errno);
    } else
        printf("the server is listening!\n");

    /*创建线程处理客户端的连接*/
    pthread_create(&thread_s[0], NULL, handle_connect, (void *)&sockfd);

    /*创建线程处理客户端的请求*/
    pthread_create(&thread_s[1], NULL, handle_request, NULL);

    /*等待线程结束*/
    for (i = 0; i < THREADNUM; i++) {
        pthread_join(thread_s[i], NULL);
    }

    /*关闭服务器的套接字*/
    close(sockfd);
    return 0;
}